#include <iostream>
#include <assert.h>
#include <typeinfo>
#include <string>
#include <any>

class Any
{
    private:
        class holder //父类
        {
            public:
                virtual ~holder() {}
                virtual const std::type_info& type() = 0; 
                virtual holder *clone() = 0; 
        };
        template<class T>
        class placeholder:public holder //子类
        {
            public:
                placeholder(const T& val) :_val(val) {}
                //获取子类当前的数据类型T
                virtual const std::type_info& type() { return typeid(T); } 
                //针对当前对象自身克隆出新的子类对象出来
                virtual holder *clone() { return new placeholder(_val); }
            public:
                T _val; //保存任意类型的数据
        };
        holder *_content;
    public:
        Any(): _content(nullptr) {}; //构造空容器

        template<class T>
        //构造任意类型的通用容器.我们并不知道类型是什么，设置成模板函数
        Any(const T &val): _content(new placeholder<T>(val)) {}; 
        //根据其他的容器构造新容器
        //不是保存对方容器数据的指针，而是容器中的数据
        Any(const Any &other): _content(other._content ? other._content->clone() : nullptr){}; 

        //销毁_content
        ~Any() {delete _content; } 

        template<class T>
        //获取子类对象当中保存数据的指针 &val
        T *get() 
        {
            //想要获取的数据类型，必须和保存的数据类型一致
            assert(typeid(T) == _content->type());
            //注意优先级：先强转，再取出_val，最后取_val的地址
            return &((placeholder<T>*)_content)->_val;
        }

        Any& swap(Any& other)
        {
            std::swap(_content, other._content);
            return *this;
        }

        template<class T>
        //赋值运算符重载 - 赋值各种类型的数据
        Any& operator=(const T& val) 
        {
            //为val构造一个临时通用容器，然后与当前容器自身进行指针交换，临时对象释放3的时候，
            //原先保存的数据也被释放了
            Any(val).swap(*this);
            return *this;
        } 
        //赋值运算符重载 - 赋值各种类型的通用容器
        Any& operator=(const Any& other) 
        {
            Any(other).swap(*this);
            return *this;
        } 
 
};

class Test
{
    public:
        Test() {std::cout << "构造" << std::endl; }
        Test(const Test& t) {std::cout << "拷贝" << std::endl; }
        ~Test() {std::cout << "析构" << std::endl; }
};

int main()
{
    //对c++17里的any容器进行演示
    std::any a;
    a = 10;
    int *pa = std::any_cast<int>(&a);
    std::cout << *pa << std::endl;

    a = std::string("nihao");
    std::string* ps = std::any_cast<std::string>(&a);
    std::cout << *ps << std::endl; 


    //对我们自己实现的Any容器进行演示
    // Any a;

    // {
    //     Test t;
    //     a = t;
    // }

    // a = 10;
    // int *pa = a.get<int>();
    // std::cout << *pa << std::endl;

    // a = std::string("nihao");
    // std::string * ps = a.get<std::string>();
    // std::cout << *ps << std::endl;

    return 0;
}